package com.nc.delivery_project.server.db_util;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by miroshnik on 23.12.2014.
 *  
 * Load SQL statements into JVM memory and hold it.
 * DAO classes use it for DB operations. 
 */
public final class QueryManager {

    public static String QUERIES_SOURCE = "com/nc/delivery_project/sql.xml";

    private static QueryManager queryManager;

    /** SQL statements holder. 
     * <EntityName, <SQLName, SQLStatement>>
     */
    private Map<String, Map<String, String>> queries;

    private QueryManager() {
        try {
            queries = loadQueries(QUERIES_SOURCE);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        }
    }

    public static QueryManager getInstance() {
        if (queryManager == null) {
            queryManager = QueryManagerInstanceHolder.INSTANCE;
        }

        return queryManager;
    }

    /**
     * Get SQL statement* 
     * @param entityName - name of entity what SQL needed
     * @param queryName - name of needed sql statement 
     * @return sql query
     */
    public String getQuery(String entityName, String queryName) {
        String query = null;

        Map<String, String> currQueries = queries.get(entityName.toLowerCase());

        if (currQueries != null) {
            query = currQueries.get(queryName);
        }

        return query;
    }

    public Map<String, Map<String, String>> getQueries() {
        return queries;
    }

    private Map<String, Map<String, String>> loadQueries(String path) 
            throws ParserConfigurationException, IOException, SAXException {
        
        Map<String, Map<String, String>> queries = new HashMap<>();
        
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        
        Document doc = builder.parse(Thread.currentThread().getContextClassLoader().getResource(path).openStream());
        Element root = doc.getDocumentElement();
        NodeList entities = root.getChildNodes();

        for (int i = 0; i < entities.getLength(); i++) {
            Node entity = entities.item(i);
            
            NodeList sqlStatements = entity.getChildNodes();
            Map<String, String> sqlMap = new HashMap<>();
            for (int j = 0; j < sqlStatements.getLength(); j++) {
                Node node = sqlStatements.item(j);
                if (node instanceof Element) {
                    Element sqlStatement = (Element) node;
                    sqlMap.put(sqlStatement.getTagName(), sqlStatement.getTextContent().trim());
                }
            }
            
            if (entity instanceof Element)
                queries.put(entity.getNodeName(), sqlMap);
        }
        
        return queries;
    }

    private static class QueryManagerInstanceHolder {
        private static QueryManager INSTANCE = new QueryManager();
    }
    
}
